/******************************************************************
 * @version      : 1.0
 * @Author       : zhl
 * @Date         : 2023-06-29 13:58:02
 * @LastEditors  : zhl
 * @E-Mail       : zhll168@163.com
 * @Description  : 业务描述
 ******************************************************************/
#include "DLT698-Frame.h"
#include "CLogger.h"
#include "check_code.h"


DLT698Frame DLT698Frame::c_frame;

uint8_t DLT698Frame::get_piid(){
    static PIID piid;
    piid.fields.priority = 0;
    piid.fields.reserve = 0;
    if(63 < piid.fields.sn){
        piid.fields.sn = 0;
    } else {
        piid.fields.sn++;
    }
    return piid.value;
}

uint8_t DLT698Frame::get_piid_acd(){
    static PIID_ACD piid_acd;
    piid_acd.fields.priority = 0;
    piid_acd.fields.acd = 0;
    if(63 < piid_acd.fields.sn){
        piid_acd.fields.sn = 0;
    } else {
        piid_acd.fields.sn++;
    }
    return piid_acd.value;
}


DLT698Frame::DLT698Frame(/* args */){
}

DLT698Frame::~DLT698Frame(){
}

DLT698Frame& DLT698Frame::getInstance(){
    return c_frame;
}

int DLT698Frame::get_frame(const uint8_t *frame, int len, DLT698_FRAME& dlt698Frame){
    uint8_t *pFrame = get_real_data(frame, len);
    // DLT698_FRAME  dlt698Frame;
    
    if(NULL != pFrame){
        if(0 > get_apdu(pFrame, len, dlt698Frame.apdu)){
            return -1;
        }
        dlt698Frame.c.value = get_frame_c(pFrame, len);
        dlt698Frame.ca = get_frame_ca(pFrame, len);
        dlt698Frame.em = get_frame_em(pFrame, len);
        dlt698Frame.fcs = get_frame_fcs(pFrame, len);
        dlt698Frame.hcs = get_frame_hcs(pFrame, len);
        dlt698Frame.l = get_frame_l(pFrame, len);
        if(NULL == get_frame_lc(pFrame, len)){
            memset(dlt698Frame.lc, 0, sizeof(dlt698Frame.lc));
        } else {
            memcpy(dlt698Frame.lc, get_frame_lc(pFrame, len), sizeof(dlt698Frame.lc));
        }
        dlt698Frame.sa_fc.value = get_frame_sa_sc(pFrame, len);
        memcpy(dlt698Frame.sa, get_frame_sa(pFrame, len).second, dlt698Frame.sa_fc.sa_fc.addr_len);
        return 0;
    }
    return -1;
}

const uint8_t* DLT698Frame::get_frame_lc(const uint8_t *frame, int len){
    if((NULL == frame) || (4 > len)){
        return NULL;
    }
    if(0x68 != frame[0]){
        return frame;
    } else {
        return NULL;
    }
}
/**
 * @brief 起始码
*/
uint8_t  DLT698Frame::get_frame_sc(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     return pFrame[0];
    // }
    // return 0;
    if((NULL == frame) || (1 > len)){
        return 0;
    }
    return frame[0];
}

uint16_t DLT698Frame::get_frame_l(const uint8_t *frame, int len){
    //需要判断大小端
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     return *(uint16_t *)(pFrame+1);
    // }
    // return 0;

    if((NULL == frame) || (3 > len)){
        return 0;
    }
    return *(uint16_t *)(frame+1);
}

uint8_t  DLT698Frame::get_frame_c(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     return pFrame[3];
    // }
    // return 0;
    if((NULL == frame) || (4 > len)){
        return 0;
    }
    return frame[3];
}

uint8_t  DLT698Frame::get_frame_sa_sc(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     return pFrame[4];
    // }
    // return 0;
    if((NULL == frame) || (5 > len)){
        return 0;
    }
    return frame[4];
}

std::pair<uint8_t, uint8_t*>  DLT698Frame::get_frame_sa(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     int len = get_frame_sa_sc_addr_len(pFrame[4]);
    //     int offset = len+5;
    //     return std::make_pair(len, pFrame+offset);
    // }
    // return std::make_pair((uint8_t)0, (uint8_t *)NULL);
    if((NULL == frame) || (6 > len)){
        return std::make_pair((uint8_t)0, (uint8_t *)NULL);
    }
    int addr_len = get_frame_sa_sc_addr_len(frame[4]);
    int offset = 5;
    return std::make_pair(addr_len, (uint8_t *)frame+offset);
}

uint8_t  DLT698Frame::get_frame_ca(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     int idx = 5+get_frame_sa_sc_addr_len(frame[4]);
    //     return pFrame[idx];
    // }

    // return 0;
    if((NULL == frame) || (6 > len)){
        return 0;
    }
    int idx = 5+get_frame_sa_sc_addr_len(frame[4]);
    return frame[idx];
}

uint16_t DLT698Frame::get_frame_hcs(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     int offset = 5+get_frame_sa_sc_addr_len(pFrame[4])+1;
    //     return *(uint16_t *)(pFrame+offset);
    // }
    // return 0;
    if((NULL == frame) || (7 > len)){
        return 0;
    }
    int offset = 5+get_frame_sa_sc_addr_len(frame[4])+1;
    return *(uint16_t *)(frame+offset);
}
#if 0
std::pair<uint16_t, uint8_t*> DLT698Frame::get_apdu(const uint8_t *frame, int len){

    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     uint16_t len = *(uint16_t *)(pFrame+1);
    //     int offset = 5+get_frame_sa_sc_addr_len(pFrame[4])+1+2;
    //     len -= offset;
    //     len -= 1;
    //     return std::make_pair(len, pFrame+offset);
    // }
    // return std::make_pair((uint16_t)0, (uint8_t *)NULL);

    if((NULL == frame) || (8 > len)){
        return std::make_pair((uint16_t)0, (uint8_t *)NULL);
    }
    uint16_t len = *(uint16_t *)(frame+1);
    int offset = 5+get_frame_sa_sc_addr_len(frame[4])+1+2;
    len -= offset;
    len -= 1;
    return std::make_pair(len, (uint8_t *)frame+offset);
}
#endif
int DLT698Frame::get_apdu(const uint8_t *frame, int len, APDU& apdu){

    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     uint16_t len = *(uint16_t *)(pFrame+1);
    //     int offset = 5+get_frame_sa_sc_addr_len(pFrame[4])+1+2;
    //     len -= offset;
    //     len -= 1;
    //     return std::make_pair(len, pFrame+offset);
    // }
    // return std::make_pair((uint16_t)0, (uint8_t *)NULL);
    // APDU apdu;
    if((NULL == frame) || (8 > len)){
        return -1;
    }
    uint16_t data_len = *(uint16_t *)(frame+1);
    int offset = 5+get_frame_sa_sc_addr_len(frame[4])+1+2;
    apdu.apdu = (uint8_t *)frame+offset;
    apdu.apdu_len = data_len - offset -1;
    apdu.apdu_tag = apdu.apdu[0];
    apdu.func_tag = apdu.apdu[1];
    apdu.piid.value = apdu.apdu[2];
    return 0;
}

uint16_t DLT698Frame::get_apdu_len(const uint8_t *frame, int len){

    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     uint16_t len = *(uint16_t *)(pFrame+1);
    //     int offset = 5+get_frame_sa_sc_addr_len(pFrame[4])+1+2;
    //     len -= offset;
    //     len -= 2;
    //     return len;
    // }
    // return 0;

    if((NULL == frame) || (8 > len)){
        return 0;
    }
    uint16_t apdu_len = *(uint16_t *)(frame+1);
    int offset = 5+get_frame_sa_sc_addr_len(frame[4])+1+2;
    apdu_len -= offset;
    apdu_len -= 2;
    return apdu_len;
}

uint8_t DLT698Frame::get_apdu_type(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     uint16_t len = *(uint16_t *)(pFrame+1);
    //     int offset = 5+get_frame_sa_sc_addr_len(pFrame[4])+1+2;
    //     len -= offset;
    //     len -= 2;
    //     return *((uint8_t*)(pFrame+offset));
    // }
    // return 0;

    if((NULL == frame) || (8 > len)){
        return 0;
    }
    int offset = 5+get_frame_sa_sc_addr_len(frame[4])+1+2;
    return *((uint8_t*)(frame+offset));
}

uint16_t DLT698Frame::get_frame_fcs(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     int offset = get_frame_l(frame, len)+1-2;
    //     return *(uint16_t*)(pFrame+offset);
    // }
    // return 0;

    if((NULL == frame) || (10 > len)){
        return 0;
    }
    int offset = get_frame_l(frame, len)+1-2;
    return *(uint16_t*)(frame+offset);
}

uint8_t DLT698Frame::get_frame_em(const uint8_t *frame, int len){
    // uint8_t *pFrame = get_real_data(frame, len);
    // if(NULL != pFrame){
    //     int offset = get_frame_l(frame, len)+1;
    //     return pFrame[offset];
    // }
    // return 0;

    if((NULL == frame) || (10 > len)){
        return 0;
    }
    int offset = get_frame_l(frame, len)+1;
    return frame[offset];
}

int DLT698Frame::check_hcs(const uint8_t* frame, int len){
    if((NULL == frame) || (1 > len)){
        return 0;
    }
    int head_len = 4+get_frame_sa_sc_addr_len(frame[4])+1;
    uint16_t cs = get_fcs16(PPPINITFCS16, (unsigned char *)frame+1, head_len);
    return cs == get_frame_hcs(frame, len);
}

int DLT698Frame::check_fcs(const uint8_t* frame, int len){
    if((NULL == frame) || (1 > len)){
        return 0;
    }
    uint16_t cs = get_fcs16(PPPINITFCS16, (unsigned char *)frame+1, len-4);
    return cs == get_frame_fcs(frame, len);
}

uint8_t*  DLT698Frame::get_real_data(const uint8_t *frame, int len){

    if((NULL == frame) || (len < 12)){
        CLogger::getInstance()->LOG_W("无效的DL/T698帧数据");
        return NULL;
    }
    uint8_t* real_frame = NULL;
    int real_frame_len = len;
    if(0 == memcmp(frame, c_dlt698_frame.lc, sizeof(c_dlt698_frame.lc))){
        if(0x68 == frame[4]){
            real_frame_len = len-4;
            real_frame = (uint8_t *)(frame+4);
        }
    } else if(0x68 == frame[0]){
        real_frame = (uint8_t *)frame;
    }
    if((NULL != real_frame) && (1 == check_hcs(real_frame, real_frame_len)) && (1 == check_fcs(real_frame, real_frame_len))){
        return real_frame;
    }
    return NULL;
}
//==============================================
//获取控制域格式化内容 开始
TRANSMIT_INITIATE_DIRECTION DLT698Frame::get_frame_c_direction(const uint8_t c){
    return (TRANSMIT_INITIATE_DIRECTION)((c >> 6) & 0x03);
}
uint8_t DLT698Frame::get_frame_c_subframe_flag(const uint8_t c){
    return ((c >> 5) & 0x01);
}
uint8_t DLT698Frame::get_frame_c_mix_code(const uint8_t c){
    return ((c >> 3) & 0x01);
}
uint8_t DLT698Frame::get_frame_c_func_code(const uint8_t c){
    return (c & 0x07);
}
//获取控制域格式化内容 结束
//==============================================
//获取地址域格式化内容
DLT698_FRAME_SA_TYPE DLT698Frame::get_frame_sa_sc_addr_type(const uint8_t sa_sc){
    return (DLT698_FRAME_SA_TYPE)((sa_sc >> 6) & 0x03);
}
uint8_t DLT698Frame::get_frame_sa_sc_logic_addr(const uint8_t sa_sc){
    return ((sa_sc >> 4) & 0x03);
}
uint8_t DLT698Frame::get_frame_sa_sc_addr_len(const uint8_t sa_sc){
    return (sa_sc & 0x0F)+1;
}